#pragma once
#include "JsonParser.hpp"

#pragma mark - enum

// template <>
// class JsonParser<enum class>
// {};

#pragma mark - bool

template <>
class JsonParser<bool>
{
public:
    bool empty(const bool& value) const {return value==false;}
    bool read(const rapidjson::Value& doc, bool& value) {
        if (doc.IsBool()) {
            value = doc.GetBool();
            return true;
        }
        return false;
    }
    bool write(rapidjson::Document::AllocatorType& allocator, rapidjson::Value& doc, const bool& value) const {
        if (doc.IsArray()) {
            rapidjson::Value temp;
            write(allocator, temp, value);
            doc.PushBack(temp, allocator);
        } else {
            doc.SetBool(value);
        }
        return true;
    }

    bool from_key(const std::string& key, bool& value) const {
        if (key == "true") {
            value = true;
        } else {
            value = false;
        }
        return true;
    }
    bool to_key(const bool& value, std::string& key) const {
        key = value ? "ture" : "false";
        return true;
    }
};

#pragma mark - int

template <>
class JsonParser<int8_t>
{
public:
    bool empty(const int8_t& value) const {return value==0;}
    bool read(const rapidjson::Value& doc, int8_t& value) {
        if (doc.IsInt()) {
            value = doc.GetInt();
            return true;
        }
        return false;
    }
    bool write(rapidjson::Document::AllocatorType& allocator, rapidjson::Value& doc, const int8_t& value) const {
        if (doc.IsArray()) {
            rapidjson::Value temp;
            write(allocator, temp, value);
            doc.PushBack(temp, allocator);
        }
        else {
            doc.SetInt(value);
        }
        return true;
    }

    bool from_key(const std::string& key, int8_t& value) const {
        value = std::stoi(key);
        return true;
    }
    bool to_key(const int8_t& value, std::string& key) const {
        key = std::to_string(value);
        return true;
    }
};

template <>
class JsonParser<int16_t>
{
public:
    bool empty(const int16_t& value) const {return value==0;}
    bool read(const rapidjson::Value& doc, int16_t& value) {
        if (doc.IsInt()) {
            value = doc.GetInt();
            return true;
        }
        return false;
    }
    bool write(rapidjson::Document::AllocatorType& allocator, rapidjson::Value& doc, const int16_t& value) const {
        if (doc.IsArray()) {
            rapidjson::Value temp;
            write(allocator, temp, value);
            doc.PushBack(temp, allocator);
        }
        else {
            doc.SetInt(value);
        }
        return true;
    }

    bool from_key(const std::string& key, int16_t& value) const {
        value = std::stoi(key);
        return true;
    }
    bool to_key(const int16_t& value, std::string& key) const {
        key = std::to_string(value);
        return true;
    }
};

template <>
class JsonParser<int32_t>
{
public:
    bool empty(const int32_t& value) const {return value==0;}
    bool read(const rapidjson::Value& doc, int32_t& value) {
        if (doc.IsInt()) {
            value = doc.GetInt();
            return true;
        }
        return false;
    }
    bool write(rapidjson::Document::AllocatorType& allocator, rapidjson::Value& doc, const int32_t& value) const {
        if (doc.IsArray()) {
            rapidjson::Value temp;
            write(allocator, temp, value);
            doc.PushBack(temp, allocator);
        }
        else {
            doc.SetInt(value);
        }
        return true;
    }

    bool from_key(const std::string& key, int32_t& value) const {
        value = std::stoi(key);
        return true;
    }
    bool to_key(const int32_t& value, std::string& key) const {
        key = std::to_string(value);
        return true;
    }
};

template <>
class JsonParser<long>
{
public:
    bool empty(const long& value) const {return value==0;}
    bool read(const rapidjson::Value& doc, long& value) {
        if (doc.IsInt64()) {
            value = doc.GetInt64();
            return true;
        }
        return false;
    }
    bool write(rapidjson::Document::AllocatorType& allocator, rapidjson::Value& doc, const long& value) const {
        if (doc.IsArray()) {
            rapidjson::Value temp;
            write(allocator, temp, value);
            doc.PushBack(temp, allocator);
        }
        else {
            doc.SetInt64(value);
        }
        return true;
    }

    bool from_key(const std::string& key, long& value) const {
        value = std::stol(key);
        return true;
    }
    bool to_key(const long& value, std::string& key) const {
        key = std::to_string(value);
        return true;
    }
};

template <>
class JsonParser<long long>
{
public:
    bool empty(const long long& value) const {return value==0;}
    bool read(const rapidjson::Value& doc, long long& value) {
        if (doc.IsInt64()) {
            value = doc.GetInt64();
            return true;
        }
        return false;
    }
    bool write(rapidjson::Document::AllocatorType& allocator, rapidjson::Value& doc, const long long& value) const {
        if (doc.IsArray()) {
            rapidjson::Value temp;
            write(allocator, temp, value);
            doc.PushBack(temp, allocator);
        }
        else {
            doc.SetInt64(value);
        }
        return true;
    }

    bool from_key(const std::string& key, long long& value) const {
        value = std::stoll(key);
        return true;
    }
    bool to_key(const long long& value, std::string& key) const {
        key = std::to_string(value);
        return true;
    }
};

#pragma mark - uint

template <>
class JsonParser<uint8_t>
{
public:
    bool empty(const uint8_t& value) const {return value==0;}
    bool read(const rapidjson::Value& doc, uint8_t& value) {
        if (doc.IsUint()) {
            value = doc.GetUint();
            return true;
        }
        return false;
    }
    bool write(rapidjson::Document::AllocatorType& allocator, rapidjson::Value& doc, const uint8_t& value) const {
        if (doc.IsArray()) {
            rapidjson::Value temp;
            write(allocator, temp, value);
            doc.PushBack(temp, allocator);
        }
        else {
            doc.SetUint(value);
        }
        return true;
    }

    bool from_key(const std::string& key, int8_t& value) const {
        value = std::stoul(key);
        return true;
    }
    bool to_key(const int8_t& value, std::string& key) const {
        key = std::to_string(value);
        return true;
    }
};

template <>
class JsonParser<uint16_t>
{
public:
    bool empty(const uint16_t& value) const {return value==0;}
    bool read(const rapidjson::Value& doc, uint16_t& value) {
        if (doc.IsUint()) {
            value = doc.GetUint();
            return true;
        }
        return false;
    }
    bool write(rapidjson::Document::AllocatorType& allocator, rapidjson::Value& doc, const uint16_t& value) const {
        if (doc.IsArray()) {
            rapidjson::Value temp;
            write(allocator, temp, value);
            doc.PushBack(temp, allocator);
        }
        else {
            doc.SetUint(value);
        }
        return true;
    }

    bool from_key(const std::string& key, uint16_t& value) const {
        value = std::stoul(key);
        return true;
    }
    bool to_key(const uint16_t& value, std::string& key) const {
        key = std::to_string(value);
        return true;
    }
};

template <>
class JsonParser<uint32_t>
{
public:
    bool empty(const uint32_t& value) const {return value==0;}
    bool read(const rapidjson::Value& doc, uint32_t& value) {
        if (doc.IsUint()) {
            value = doc.GetUint();
            return true;
        }
        return false;
    }
    bool write(rapidjson::Document::AllocatorType& allocator, rapidjson::Value& doc, const uint32_t& value) const {
        if (doc.IsArray()) {
            rapidjson::Value temp;
            write(allocator, temp, value);
            doc.PushBack(temp, allocator);
        }
        else {
            doc.SetUint(value);
        }
        return true;
    }

    bool from_key(const std::string& key, uint32_t& value) const {
        value = std::stoul(key);
        return true;
    }
    bool to_key(const uint32_t& value, std::string& key) const {
        key = std::to_string(value);
        return true;
    }
};

template <>
class JsonParser<unsigned long>
{
public:
    bool empty(const unsigned long& value) const {return value==0;}
    bool read(const rapidjson::Value& doc, unsigned long& value) {
        if (doc.IsUint64()) {
            value = doc.GetUint64();
            return true;
        }
        return false;
    }
    bool write(rapidjson::Document::AllocatorType& allocator, rapidjson::Value& doc, const unsigned long& value) const {
        if (doc.IsArray()) {
            rapidjson::Value temp;
            write(allocator, temp, value);
            doc.PushBack(temp, allocator);
        }
        else {
            doc.SetUint64(value);
        }
        return true;
    }

    bool from_key(const std::string& key, unsigned long& value) const {
        value = std::stoull(key);
        return true;
    }
    bool to_key(const unsigned long& value, std::string& key) const {
        key = std::to_string(value);
        return true;
    }
};

template <>
class JsonParser<unsigned long long>
{
public:
    bool empty(const unsigned long long& value) const {return value==0;}
    bool read(const rapidjson::Value& doc, unsigned long long& value) {
        if (doc.IsUint64()) {
            value = doc.GetUint64();
            return true;
        }
        return false;
    }
    bool write(rapidjson::Document::AllocatorType& allocator, rapidjson::Value& doc, const unsigned long long& value) const {
        if (doc.IsArray()) {
            rapidjson::Value temp;
            write(allocator, temp, value);
            doc.PushBack(temp, allocator);
        }
        else {
            doc.SetUint64(value);
        }
        return true;
    }

    bool from_key(const std::string& key, unsigned long long& value) const {
        value = std::stoull(key);
        return true;
    }
    bool to_key(const unsigned long long& value, std::string& key) const {
        key = std::to_string(value);
        return true;
    }
};

#pragma mark - float

template <>
class JsonParser<float>
{
public:
    bool empty(const float& value) const {return value==0.f;}
    bool read(const rapidjson::Value& doc, float& value) {
        if (doc.IsFloat()) {
            value = doc.GetFloat();
            return true;
        }
        return false;
    }
    bool write(rapidjson::Document::AllocatorType& allocator, rapidjson::Value& doc, const float& value) const {
        if (doc.IsArray()) {
            rapidjson::Value temp;
            write(allocator, temp, value);
            doc.PushBack(temp, allocator);
        } else {
            doc.SetFloat(value);
        }
        return true;
    }
};

template <>
class JsonParser<double>
{
public:
    bool empty(const double& value) const {return value==0.0;}
    bool read(const rapidjson::Value& doc, double& value) {
        if (doc.IsDouble()) {
            value = doc.GetDouble();
            return true;
        }
        return false;
    }
    bool write(rapidjson::Document::AllocatorType& allocator, rapidjson::Value& doc, const double& value) const {
        if (doc.IsArray()) {
            rapidjson::Value temp;
            write(allocator, temp, value);
            doc.PushBack(temp, allocator);
        } else {
            doc.SetDouble(value);
        }
        return true;
    }
};
